// HSS.Forms.Design.CustomPropertyDescriptor.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       CustomPropertyDescriptor.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Forms.Design
{
	#region Using Directives
	using System;

	#endregion

	#region CustomPropertyDescriptor
	/// <summary>
	/// CustomPropertyDescriptor implements ICustomTypeDescriptor and derives ExpandableObjectConverter.
	/// This class can be instantiated and properties to this class can
	/// be added dynamically using AddProperty(string _propertyName, object _propertyValue, string propDesc, 
	/// string propCat,  System.Type _propertyType, bool _isReadOnly, bool isExpandable). 
	/// </summary>
	[System.ComponentModel.TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
	[System.ComponentModel.ToolboxItem(false)]
	public class CustomPropertyDescriptor : System.ComponentModel.Component, System.ComponentModel.ICustomTypeDescriptor
	{
		#region Fields
		private System.ComponentModel.PropertyDescriptorCollection propertyCollection;
		#endregion

		#region Constructor
		/// <summary>
		/// Constructor of CustomPropertyDescriptor which initializes the new PropertyDescriptorCollection.
		/// </summary>
		public CustomPropertyDescriptor()
		{
			propertyCollection = new System.ComponentModel.PropertyDescriptorCollection(new System.ComponentModel.PropertyDescriptor[] { });
		}
		/// <summary>
		/// Constructor of CustomPropertyDescriptor
		/// </summary>
		/// <param name="PropertyCollection">PropertyDescriptorCollection for this CustomPropertyDescriptor</param>
		public CustomPropertyDescriptor(System.ComponentModel.PropertyDescriptorCollection PropertyCollection)
		{
			propertyCollection = PropertyCollection;
		}

		#endregion

		#region Methods
		/// <summary>
		/// Adds a DynamicProperty to the PropertyDescriptorCollection.
		/// </summary>
		/// <param name="PasswordCharacter">The Password Character to mask the Value</param>
		/// <param name="Name">The Property Name</param>
		/// <param name="Value">The Property Value</param>
		/// <param name="Description">The Property Description</param>
		/// <param name="Category">The Property Category</param>
		/// <param name="PropertyType">The Property Type</param>
		/// <param name="ReadOnly">Is the Property Read Only</param>
		public void AddProperty(string PasswordCharacter, string Name, object Value, string Description, string Category, System.Type PropertyType, bool ReadOnly)
		{
			Attribute[] attributes = PropertyType.GetCustomAttributes(true) as Attribute[];
			DynamicProperty p = new DynamicProperty(PasswordCharacter, Name, Value, Description, Category, PropertyType, ReadOnly, attributes);
			propertyCollection.Add(p);
		}

		/// <summary>
		/// Adds a DynamicProperty to the PropertyDescriptorCollection.
		/// </summary>
		/// <param name="DescriptorProperty">DynamicProperty Instance to add</param>
		public void AddProperty(DynamicProperty DescriptorProperty)
		{
			propertyCollection.Add(DescriptorProperty);
		}

		/// <summary>
		/// GetClassName
		/// </summary>
		/// <returns></returns>
		public string GetClassName()
		{
			return (System.ComponentModel.TypeDescriptor.GetClassName(this, true));
		}

		/// <summary>
		/// GetAttributes
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.AttributeCollection GetAttributes()
		{
			System.ComponentModel.AttributeCollection ac = System.ComponentModel.TypeDescriptor.GetAttributes(this, true);
			return ac;
		}

		/// <summary>
		/// GetComponentName
		/// </summary>
		/// <returns></returns>
		public string GetComponentName()
		{
			return (System.ComponentModel.TypeDescriptor.GetComponentName(this, true));
		}

		/// <summary>
		/// GetConverter
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.TypeConverter GetConverter()
		{
			return System.ComponentModel.TypeDescriptor.GetConverter(this, true);
		}

		/// <summary>
		/// GetDefaultEvent
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.EventDescriptor GetDefaultEvent()
		{
			return (System.ComponentModel.TypeDescriptor.GetDefaultEvent(this, true));
		}

		/// <summary>
		/// GetDefaultProperty
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.PropertyDescriptor GetDefaultProperty()
		{
			System.ComponentModel.PropertyDescriptorCollection props = GetAllProperties();

			if (props.Count > 0)
			{
				return (props[0]);
			}
			else
				return (null);
		}

		/// <summary>
		/// GetEditor
		/// </summary>
		/// <param name="editorBaseType"></param>
		/// <returns></returns>
		public virtual object GetEditor(Type editorBaseType)
		{

			return (System.ComponentModel.TypeDescriptor.GetEditor(this, editorBaseType, true));
		}

		/// <summary>
		/// EventDescriptorCollection
		/// </summary>
		/// <param name="attributes"></param>
		/// <returns></returns>
		public System.ComponentModel.EventDescriptorCollection GetEvents(Attribute[] attributes)
		{
			return (System.ComponentModel.TypeDescriptor.GetEvents(this, attributes, true));
		}

		/// <summary>
		///
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.EventDescriptorCollection GetEvents()
		{
			return (System.ComponentModel.TypeDescriptor.GetEvents(this, true));
		}

		/// <summary>
		///
		/// </summary>
		/// <param name="attributes"></param>
		/// <returns></returns>
		public System.ComponentModel.PropertyDescriptorCollection GetProperties(Attribute[] attributes)
		{
			return (GetAllProperties());
		}

		/// <summary>
		///
		/// </summary>
		/// <returns></returns>
		public System.ComponentModel.PropertyDescriptorCollection GetProperties()
		{
			return (GetAllProperties());
		}

		/// <summary>
		///
		/// </summary>
		/// <param name="pd"></param>
		/// <returns></returns>
		public object GetPropertyOwner(System.ComponentModel.PropertyDescriptor pd)
		{
			return (this);
		}

		/// <summary>
		///	Helper method to return the PropertyDescriptorCollection or our Dynamic Properties
		/// </summary>
		/// <returns>PropertyDescriptorCollection</returns>
		private System.ComponentModel.PropertyDescriptorCollection GetAllProperties()
		{
			return propertyCollection;
		}

		#endregion

		#region Properties
		/// <summary>
		/// Indexer for this class - returns a DynamicProperty by index position.
		/// </summary>
		public DynamicProperty this[int index]
		{
			get
			{
				return (DynamicProperty)propertyCollection[index];
			}
		}

		/// <summary>
		/// Overloaded Indexer for this class - returns a DynamicProperty by name.
		/// </summary>
		public DynamicProperty this[string name]
		{
			get
			{
				return (DynamicProperty)propertyCollection[name];
			}
		}

		/// <summary>
		/// Evalute whether or not to mask the value
		/// </summary>
		/// <param name="Value">The string Value to mask</param>
		/// <param name="PasswordCharacter">The Password Character to use for masking</param>
		/// <returns>The String containing the Value</returns>
		public static string EvalPasswordChar(string Value, string PasswordCharacter)
		{
			if (!string.IsNullOrEmpty(PasswordCharacter))
			{
				if (PasswordCharacter.Length > 1)
					PasswordCharacter = PasswordCharacter.Substring(0, 1);
				string ret = new string(char.Parse(PasswordCharacter), _passwordMaskLength);
				return ret;
			}
			else
				return Value;
		}
		/// <summary>
		/// The number of Masked Character to display in place of a properties raw value
		/// </summary>
		public static int PasswordMaskLength
		{
			get { return _passwordMaskLength; }
			set { _passwordMaskLength = value; }
		} static int _passwordMaskLength = 15;
		#endregion
	}
	#endregion

	#region DynamicProperty
	/// <summary>
	///	This is a custom PropertyDescriptor
	/// </summary>
	public class DynamicProperty : System.ComponentModel.PropertyDescriptor
	{
		#region Constructors
		/// <summary>
		/// DynamicProperty Constructor and sets all the properties
		/// </summary>
		/// <param name="PasswordCharacter">The Password Character to mask the Value</param>
		/// <param name="Name">The Property Name</param>
		/// <param name="Value">The Property Value</param>
		/// <param name="Description">The Property Description</param>
		/// <param name="Category">The Property Category</param>
		/// <param name="PropertyType">The Property Type</param>
		/// <param name="ReadOnly">Is the Property Read Only</param>
		/// <param name="Attributes">The attributes for this Property</param>
		public DynamicProperty(string PasswordCharacter, string Name, object Value, string Description, string Category, Type PropertyType, bool ReadOnly, Attribute[] Attributes)
			: base(Name, Attributes)
		{
			_passwordCharacter = PasswordCharacter;
			_propertyName = Name;
			_propertyValue = Value;
			_propertyDescription = Description;
			_propertyCategory = Category;
			_propertyType = PropertyType;
			_isReadOnly = ReadOnly;
			if (Value.GetType() == typeof(string))
				_propertyPasswordValue = CustomPropertyDescriptor.EvalPasswordChar(Value.ToString(), PasswordCharacter);
		}

		/// <summary>
		/// DynamicProperty Constructor and sets all the properties
		/// </summary>
		/// <param name="PropertyInstance">DynamicProperty</param>
		public DynamicProperty(DynamicProperty PropertyInstance)
			: base(PropertyInstance._propertyName, PropertyInstance.AttributeArray)
		{
			this._passwordCharacter = PropertyInstance.PasswordCharacter;
			this._propertyName = PropertyInstance.PropertyName;
			this._propertyValue = PropertyInstance.PropertyValue;
			this._propertyPasswordValue = PropertyInstance.PropertyPasswordValue;
			this._propertyDescription = PropertyInstance.Description;
			this._propertyCategory = PropertyInstance.Category;
			this._propertyType = PropertyInstance.PropertyType;
			this._isReadOnly = PropertyInstance.IsReadOnly;
		}

		#endregion

		#region Methods
		/// <summary>
		/// Indicates if the Extended type can have it's reevaluated. Default is false.
		/// </summary>
		/// <param name="component">The component to reset</param>
		/// <returns>true if the can reset value.
		/// Default is true</returns>
		public override bool CanResetValue(object component)
		{
			return false;
		}
		/// <summary>
		/// Get the underlying value for this property for displaying
		/// </summary>
		/// <param name="component">Component Source</param>
		/// <returns>An object containing the value</returns>
		public override object GetValue(object component)
		{
			if (!string.IsNullOrEmpty(this._passwordCharacter))
				return _propertyPasswordValue;
			else
				return _propertyValue;
		}
		/// <summary>
		/// Sets the value of a property
		/// </summary>
		/// <param name="component"></param>
		/// <param name="value"></param>
		public override void SetValue(object component, object value)
		{
			if (!string.IsNullOrEmpty(this._passwordCharacter))
				_propertyPasswordValue = CustomPropertyDescriptor.EvalPasswordChar(value.ToString(), this._passwordCharacter);
			_propertyValue = value;
		}
		/// <summary>
		/// Resets the value of a property
		/// </summary>
		/// <param name="component"></param>
		public override void ResetValue(object component)
		{
			_propertyValue = null;
		}
		/// <summary>
		/// Indicates if the Property Descriptor should serialize
		/// </summary>
		/// <param name="component">The component to evaluate</param>
		/// <returns>Hard Coded to false.</returns>
		public override bool ShouldSerializeValue(object component)
		{
			return false;
		}

		/// <summary>
		/// Get the undelying value for this property without password masking
		/// </summary>
		/// <returns>An object containing the value</returns>
		public object GetRawValue()
		{
			return _propertyValue;
		}
		#endregion

		#region Properties
		/// <summary>
		/// The name of the Property
		/// </summary>
		public string PropertyName
		{
			get { return _propertyName; }
		} string _propertyName;
		/// <summary>
		/// The value of the Property
		/// </summary>
		public object PropertyValue
		{
			get { return _propertyValue; }
		} object _propertyValue;
		/// <summary>
		/// The masked value of the Property
		/// </summary>
		public object PropertyPasswordValue
		{
			get { return _propertyPasswordValue; }
		} object _propertyPasswordValue = string.Empty;
		/// <summary>
		/// Get the Password Character
		/// </summary>
		public string PasswordCharacter
		{
			get { return this._passwordCharacter; }
		} string _passwordCharacter = string.Empty;
		/// <summary>
		/// The description for the Dynamic Property
		/// </summary>
		public override string Description
		{
			get
			{
				return _propertyDescription;
			}
		} string _propertyDescription;
		/// <summary>
		/// The category for the property
		/// </summary>
		public override string Category
		{
			get
			{
				return _propertyCategory;
			}
		} string _propertyCategory;
		/// <summary>
		/// The System.Type of the Property
		/// </summary>
		public override System.Type PropertyType
		{
			get { return _propertyType; }
		} System.Type _propertyType;
		/// <summary>
		/// Is the property read only
		/// </summary>
		public override bool IsReadOnly
		{
			get { return _isReadOnly; }
		} bool _isReadOnly;
		/// <summary>
		/// The Component Type. Hardcoded to null
		/// </summary>
		public override System.Type ComponentType
		{
			get { return null; }
		}
		#endregion
	}
	#endregion
}